﻿#define XMLWRITER
#define SERIALIZATION

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using SpicIE.Common;
using System.Windows.Forms;
using IEAccessibleTabs;
using System.IO;
using SHDocVw;
using System.Xml;
#if SERIALIZATION
using System.Xml.Serialization;
#endif


namespace TabSaver.LoadTabs
{
    /// <summary>
    /// This is a simple COM object wich implements the IOleCommandTarget.
    /// The interface is needed when a COM object shall be called via COM object invoke by another component.
    /// There are two needed interface member implementations which can be changed to match the demands of the user
    /// when the plugin is called.
    /// </summary>
    [ComVisible(true),
    ClassInterface(ClassInterfaceType.AutoDual),
    Guid(LoadTabsObject.PLUGIN_GUID),
    ProgId(LoadTabsObject.PLUGIN_PROGID)]
    public class LoadTabsObject : IOleCommandTarget
    {
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();


        public const string PLUGIN_GUID = "09AFB878-CC96-42bc-9ED7-6CD62C3C10BF";
        public const string PLUGIN_PROGID = "TabSaver.LoadTabsObject";

        public LoadTabsObject()
        {
            // nothing needs to be done here, since this plugin shall only do 
            //something when invoked by another COM object via IOleCommandTarget::Exec
        }

        #region IOLECommandTarget interface implementation
        /// <summary>
        /// interface implementation for communicating with the ole object, in this case the menuitem as com object
        /// </summary>
        /// <param name="pguidCmdGroup"></param>
        /// <param name="cCmds"></param>
        /// <param name="prgCmds"></param>
        /// <param name="pCmdText"></param>
        /// <returns>-1</returns>
        public int QueryStatus(ref Guid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
        {
            return -1;
        }


        /// <summary>
        /// interface implementation for firing the OLE Command event which can be subscribed in the intatiated class
        /// </summary>
        /// <param name="pguidCmdGroup"></param>
        /// <param name="nCmdID"></param>
        /// <param name="nCmdexecopt"></param>
        /// <param name="pvaIn"></param>
        /// <param name="pvaOut"></param>
        /// <returns>-1</returns>
        public int Exec(ref Guid pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
        {
#if SERIALIZATION
            Stream stream = null;
#endif
            Guid SID_SShellBrowser = new Guid("000214E2-0000-0000-C000-000000000046");
            Guid BrowserGUID = new Guid("00000114-0000-0000-C000-000000000046");
            Guid IIDWebBrowserApp = new Guid("0002DF05-0000-0000-C000-000000000046");
            Guid IIDWebBrowser2 = new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
            Guid iid = new Guid("00000000-0000-0000-C000-000000000046"); // IID_IUnknown
            Guid IID_ITravelLogStg = new Guid("7EBFDD80-AD18-11d3-A4C5-00C04F72D6B8");
            Guid SID_STravelLogCursor = new Guid("7EBFDD80-AD18-11d3-A4C5-00C04F72D6B8");


            try
            {
#if SERIALIZATION
                stream = File.Open(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + Path.DirectorySeparatorChar + "IETabs" + Path.DirectorySeparatorChar + "quicktabs.tab", FileMode.Open);
                XmlSerializer XMLDESERIALIZER = new XmlSerializer(typeof(BrowserSession));
                BrowserSession SavedBrowserSession = (BrowserSession)XMLDESERIALIZER.Deserialize(stream);
                stream.Close();
#endif
                IEAccessible IEAccessor = new IEAccessible();

                object navOpenInNewTab = 0x0800;
                object p = null;
                object url = "about:blank";

                System.Collections.IEnumerator windows = new SHDocVw.ShellWindowsClass().GetEnumerator();
                IWebBrowser2 WebBrowserWindow = null;
                while (windows.MoveNext())
                {
                    WebBrowserWindow = (IWebBrowser2)windows.Current;
                    try
                    {
                        if (WebBrowserWindow.HWND == GetForegroundWindow().ToInt32())
                        {
                            break;
                        }
                    }
                    catch (Exception e)
                    {
                        //MessageBox.Show(e.ToString());
                    }
                }


#if SERIALIZATION
                foreach (TabSession SavedSesssion in SavedBrowserSession.SessionEntries)
                {
                    url = SavedSesssion.TabTravelLogEntries[SavedSesssion.TabTravelLogEntries.Count - 1].URL;
                    WebBrowserWindow.Navigate2(ref url, ref navOpenInNewTab, ref p, ref p, ref p);

                    IntPtr ChildTabHwnd = IntPtr.Zero;
                    System.Threading.Thread.Sleep(1000);

                    foreach (InternetExplorer newie in IEAccessible.GetBrowserObjectsFromHandle(GetForegroundWindow()))
                    {
                        IServiceProvider ParentServiceProvider = newie as IServiceProvider;

                        IntPtr newBrowser;
                        ParentServiceProvider.QueryService(ref SID_SShellBrowser, ref BrowserGUID, out newBrowser);
                        IOleWindow ChildTabOleWindow = Marshal.GetObjectForIUnknown(newBrowser) as IOleWindow;
                        ChildTabOleWindow.GetWindow(out ChildTabHwnd);
                        if (IsWindowVisible(ChildTabHwnd))
                        {
                            break;
                        }
                    }

                    InternetExplorer ie = IEAccessible.GetTabBrowserObjectFromHandle(WebBrowserWindow.HWND, ChildTabHwnd);

                    IServiceProvider BrowserServiceProvider = ie as IServiceProvider;
                    int iHistoryCount = 0;
                    if (BrowserServiceProvider == null)
                    {
                        throw new Exception();
                    }

                    IntPtr TravelLogPointer = IntPtr.Zero;
                    int hr = BrowserServiceProvider.QueryService(ref SID_STravelLogCursor, ref IID_ITravelLogStg, out TravelLogPointer);

                    if ((TravelLogPointer == IntPtr.Zero) || (hr != 0)) //hr == 0 SUCCESS http://en.wikipedia.org/wiki/HRESULT
                    {
                        throw new Exception();
                    }

                    ITravelLogStg TravelLog = Marshal.GetObjectForIUnknown(TravelLogPointer) as ITravelLogStg;

                    if (TravelLog != null)
                    {
                        //Get the count
                        TravelLog.GetCount((int)TLMENUF.TLEF_ABSOLUTE, out iHistoryCount);
                        if (iHistoryCount == 0)
                        {
                            Debug.Print("\r\nNo history entries");
                        }

                        Debug.Print("\r\nCount =>" + iHistoryCount.ToString());

                        foreach (TabSessionEntry Entry in SavedSesssion.TabTravelLogEntries)
                        {
                            #region Create new TravelLogEntry
                            ITravelLogEntry NewEntry;
                            int resultcreate = TravelLog.CreateEntry(Entry.URL, Entry.Name, null, true, out NewEntry);
                            IntPtr crap;
                            NewEntry.GetURL(out crap);
                            Debug.Print(Marshal.PtrToStringUni(crap));
                            #endregion
                        }

                        Marshal.ReleaseComObject(TravelLog);
                    }
                }
#endif
            }
            catch (IOException)
            {
                MessageBox.Show("There are no tabs to load", "No Tabs to Load", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
            }
            finally
            {
                /*
                if (re != null)
                {
                    re.Close();
                }
                 * */
            }

            return -1;
        }
        #endregion

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool IsWindowVisible(IntPtr hWnd);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);

        enum GetWindow_Cmd : uint
        {
            GW_HWNDFIRST = 0,
            GW_HWNDLAST = 1,
            GW_HWNDNEXT = 2,
            GW_HWNDPREV = 3,
            GW_OWNER = 4,
            GW_CHILD = 5,
            GW_ENABLEDPOPUP = 6
        }

        [Flags]
        enum CLSCTX : uint
        {
            CLSCTX_INPROC_SERVER = 0x1,
            CLSCTX_INPROC_HANDLER = 0x2,
            CLSCTX_LOCAL_SERVER = 0x4,
            CLSCTX_INPROC_SERVER16 = 0x8,
            CLSCTX_REMOTE_SERVER = 0x10,
            CLSCTX_INPROC_HANDLER16 = 0x20,
            CLSCTX_RESERVED1 = 0x40,
            CLSCTX_RESERVED2 = 0x80,
            CLSCTX_RESERVED3 = 0x100,
            CLSCTX_RESERVED4 = 0x200,
            CLSCTX_NO_CODE_DOWNLOAD = 0x400,
            CLSCTX_RESERVED5 = 0x800,
            CLSCTX_NO_CUSTOM_MARSHAL = 0x1000,
            CLSCTX_ENABLE_CODE_DOWNLOAD = 0x2000,
            CLSCTX_NO_FAILURE_LOG = 0x4000,
            CLSCTX_DISABLE_AAA = 0x8000,
            CLSCTX_ENABLE_AAA = 0x10000,
            CLSCTX_FROM_DEFAULT_CONTEXT = 0x20000,
            CLSCTX_INPROC = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
            CLSCTX_SERVER = CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
            CLSCTX_ALL = CLSCTX_SERVER | CLSCTX_INPROC_HANDLER
        }

        [DllImport("ole32.dll", ExactSpelling = true, PreserveSig = false)]
        [return: MarshalAs(UnmanagedType.Interface)]
        static extern object CoCreateInstance(
           [In, MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
           [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
           CLSCTX dwClsContext,
           [In, MarshalAs(UnmanagedType.LPStruct)] Guid riid);
    }
}